﻿using Sustainalytics.DataLayer.Shared;
using System;
using System.Collections.Generic;
using Sustainalytics.Entities;
using System.Linq;
using MongoDB.Driver.Linq;
using MongoDB.Driver;

namespace Sustainalytics.DataLayer
{
    public class FiltersRepository : RepositoryCollection<Filter>, IFiltersRepository
    {
        public FiltersRepository(string cnxString)
            : base(cnxString)
        {           
        }

        //get user owned filters
        public List<Filter> GetFiltersByOwner(List<Guid> userIds, Guid? accountId, TargetType? targetType)
        {

            var filter = new List<FilterDefinition<Filter>>()
            {
                Builders<Filter>.Filter.In(f => f.OwnerUserId, userIds),
                Builders<Filter>.Filter.Ne(f=> f.Type, FilterType.Standard),
                Builders<Filter>.Filter.Ne(f => f.LastSaved, null)
            };


            if (accountId != null && accountId != Guid.Empty)
                filter.Add(Builders<Filter>.Filter.Eq(f => f.AccountId, accountId.Value));

            if (targetType != null)
                filter.Add(Builders<Filter>.Filter.Eq(f => f.TargetType, targetType.Value));

            return Collection().Find(Builders<Filter>.Filter.And(filter)).ToList();
        }

        public int GetFiltersCount(List<Guid> userIds, Guid? accountId, string filterName, TargetType? targetType, FilterType? filterType, int skip, int take)
        {
            var filter = new List<FilterDefinition<Filter>>();

            if (userIds != null && userIds.Any())
                filter.Add(Builders<Filter>.Filter.In(f => f.OwnerUserId, userIds));

            if (accountId != null && accountId != Guid.Empty)
                filter.Add(Builders<Filter>.Filter.Eq(f => f.AccountId, accountId.Value));

            if (filterName != null)
                filter.Add(Builders<Filter>.Filter.Eq(f => f.Name, filterName));

            if (targetType != null)
                filter.Add(Builders<Filter>.Filter.Eq(f => f.TargetType, targetType.Value));
            
            if (filterType != null)
                filter.Add(Builders<Filter>.Filter.Eq(f => f.Type, filterType.Value));
            
            return Collection().Find(Builders<Filter>.Filter.And(filter))
                .Skip(skip)
                .Limit(take)
                .ToList()
                .Count;
        }

        public List<Filter> GetAccountFilters(Guid accountId)
        {
            var result = this.Collection().AsQueryable().Where(f => f.AccountId == accountId).ToList();
            return result;
        }

        //gets shared filters within account
        public List<Filter> GetFiltersByAccountId(Guid userId, Guid accountId, TargetType? targetType, FilterType? filterType)
        {
            var query = this.Collection().AsQueryable().Where(f => f.AccountId == accountId && f.OwnerUserId != userId && f.LastSaved != null);

            if (targetType != null)
            {
                query = query.Where(f => f.TargetType == targetType.Value);
            }

            if (filterType != null)
            {
                query = query.Where(f => f.Type == filterType.Value);
            }

            return query.ToList();
        }

        public Filter GetFilterById(Guid filterId)
        {
            return base.Read(filterId);
        }

        public bool DeleteFilter(Guid filterId)
        {
            return base.Delete(filterId);
        }

        public bool SaveFilter(Filter filter)
        {
            if (filter == null)
            {
                throw new ArgumentException("No filter provided for saving!");
            }

            return base.CreateOrUpdate(filter);
        }

        public List<Filter> GetStandardFilters(TargetType targetType)
        {
            var result = this.Collection().AsQueryable()
                .Where(
                    f => f.Type == FilterType.Standard 
                    && f.TargetType == targetType
                    && f.Status != FilterStatus.Draft)
                    .ToList();
            return result;
        }

        public Filter GetFilterByNameAndAccountId(string filterName, Guid filterId, Guid filterAccountId, TargetType filterTargetType)
        {
            return base.ReadWhere(x=>x.Name == filterName && x.Id != filterId && x.AccountId == filterAccountId && x.TargetType == filterTargetType).FirstOrDefault();
        }

        public Filter GetFilterByNameAndUserId(string filterName, Guid filterId, Guid filterOwnerUserId, TargetType filterTargetType)
        {
            return base.ReadWhere(x => x.Name == filterName && x.Id != filterId && x.OwnerUserId == filterOwnerUserId && x.TargetType == filterTargetType).FirstOrDefault();
        }

    }

}
